# coding: utf-8
import logging

from app.modules.common import jsonFileUtil
from config import BaseConfig

from pexpect import run

from app.modules.common.Errors import ServiceError
from app.modules.common.utils import (DictUtils, FileUtil, Jinja2Utils,
                                      JsonFileUtil, PageUtils, ReUtils,
                                      SysUtils)

"""
Page管理是ws-agent的核心,目标实现按winit前端架构约束来生成页面代码,它有以下3个主要功能.
1.创建一个模块, 既底层菜单项对应的page目录, model目录和代码, 路由配置文件, 以及index页面和页面js.
2.创建一个页面, 既模块下的子页面, 并在
"""
logger = logging.getLogger(__name__)


def recreate(path, file_name, elements, models, workspace='default'):
    home_path = BaseConfig.WORKSPACES[workspace]

    # 0.校验一下path是否合法
    if not (ReUtils.is_validate_path(path) and ReUtils.is_validate_path(
            path)):
        raise ServiceError(
            u"非法的path或page, 它们只能包含英文字母, 数字和下划线 menu_path:%s" % path)
    if len(path.split("/")) != 4:
        raise ServiceError(
            u"path参数不正确, 必须为'/模块名/子模块名/子菜单名' 当前path为:%s" % path)

    # 1.计算出所有所需文件的放置位置.
    the_2nd_module_name = path.split("/")[2]
    the_3nd_module_name = path.split("/")[3]
    module_name = the_2nd_module_name + the_3nd_module_name + path

    # 2.创建page.js
    page_file_path = get_page_file_path(home_path, path, file_name)
    elements = JsonFileUtil.load(elements)
    page_content = render_page_elements(file_name=file_name,
                                        elements=elements)
    logger.info("write page info into :%s" % page_file_path)
    FileUtil.write(page_file_path, page_content)

    # 3. 维护pageEvent.js
    page_event_file_path = "%s/src/pages%s/%sEvent.js" % (
        home_path, path, file_name)
    event_content = render_page_event(menu_path=path, file_name=file_name,
                                      elements=elements, module=module_name,
                                      home_path=home_path)
    if not FileUtil.file_exists(page_event_file_path):
        FileUtil.write(page_event_file_path, event_content)

    # # 4. 维护router.js
    route_file = "%s/src/config/routes.js" % home_path
    routes_content = render_routes(path=path, file_name=file_name,
                                   models=models, home_path=home_path)
    FileUtil.replace_content(file_path=route_file,
                             match=r"([\w\W]*},)([\w\W]*)",
                             replace=r"\g<1>%s\g<2>" % route_info)


def get_page_file_path(home_path, path, file_name):
    page_file_path = "%s/src/pages%s/%s.jsx" % (home_path, path, file_name)
    if not FileUtil.file_exists(page_file_path):
        FileUtil.create_file(page_file_path)
    else:
        FileUtil.write(page_file_path, '')
    return page_file_path


# {'fromSomeWhere':['component1','component2'],'fromSomeWhere2':[...]}}
def get_import_components(elements):
    components = {}

    for item in elements:

        # 深度递归遍历子节点, 按照 [{'component_from':'component1,component2,...'}]的格式合并在一个数组里.
        if isinstance(item.get('elements'), list):
            components = DictUtils.dep_merge(components,
                                             get_import_components(
                                                 item.get('elements')))

        component = item.get('component')

        component_name = component.get('component')
        component_from = component.get('from')
        brace_away = component.get('brace_away')
        split_by = component.get('split_by')

        if component_from is None or brace_away == 'true':
            continue
        if components.get(component_from) is None:
            components[component_from] = []

        component_list = components.get(component_from)

        # 遇到需要再拆分const类型的, 组件名称要取 split_by而不是component_name
        if split_by is not None:
            component_name = split_by

        if component_name not in component_list:
            component_list.append(component_name)

    return components


def get_import_components_brace_away(elements):
    components_brace_away = {}

    for item in elements:

        if isinstance(item.get('elements'), list):
            temp_components = get_import_components_brace_away(
                item.get('elements'))

            components_brace_away = dict(components_brace_away,
                                         **temp_components)
        component = item.get('component')

        component_import = component.get('component')
        component_from = component.get('from')
        brace_away = component.get('brace_away')

        if component_from is None or brace_away != 'true':
            continue

        components_brace_away[component_import] = component_from

    return components_brace_away


def get_import_components_split_const(elements):
    const_components = {}

    for item in elements:

        # 深度递归遍历子节点, 按照 [{'component_Name':'const1,const2,...'}]的格式合并在一个数组里.
        if isinstance(item.get('elements'), list):
            const_components = DictUtils.dep_merge(const_components,
                                                   get_import_components_split_const(
                                                       item.get('elements')))

        c = item.get('component')

        component_name = c.get('component')
        split_by = c.get('split_by')

        if split_by is None:
            continue
        if const_components.get(split_by) is None:
            const_components[split_by] = []

        component_list = const_components.get(split_by)

        if component_name not in component_list:
            component_list.append(component_name)

    return const_components


def get_def_events(elements):
    funcs = {}

    for item in elements:
        # 深度递归遍历子节点, 按照 [{'$func_name':{'func_name':'$func_name'}}}]的格式合并在一个数组里, 这样啰嗦的拼法, 是为了func将来可以配置更多的信息.
        if isinstance(item.get('elements'), list):
            funcs = DictUtils.sample_merge(funcs, get_def_events(item.get('elements')))
            
        attrs = item.get('attrs')

        for attr in attrs:
            a_type = attr.get('type')
            a_func_name = attr.get('v')
            if not a_type == 'func' or  a_func_name in funcs:
                continue
            func = {'func_name':a_func_name}
            funcs[a_func_name] = func

    return funcs
    # return [
    #     {'event': 'handleSubmit2', 'dispatch': 'WarehouseManage/updateState'}]


# 创建布局页面
def render_page_elements(file_name, elements,
                         root_element='PageRootElement'):
    # 1.准备填充import部分的Component列表, 区分有无大括号.
    import_components = get_import_components(elements)

    import_components_brace_away = get_import_components_brace_away(elements)

    import_components_split_const = get_import_components_split_const(elements)

    # 2.准备event列表.
    def_events = get_def_events(elements)

    # 3.数据填充模板.
    page_data = {'page_name': file_name,
                 'components': import_components,
                 'components_brace_away': import_components_brace_away,
                 'components_split_const': import_components_split_const,
                 'events': def_events,
                 'RootElement': root_element,
                 'elements': elements}

    return Jinja2Utils.render("page.jinja2", page_data)


# 检查事件在event里面是否定义
def predefind_event(page_event_file_path, e_name):
    return False


def render_page_event(menu_path, file_name, elements, module, home_path):
    return Jinja2Utils.render("event.jinja2",
                              {'module': module})
    # # 获取所有事件.
    # def_events = get_def_events(elements)
    # def_events_content = ''
    # for event in def_events:

    #     e_name = event.get('event')
    #     e_dispatch_path = event.get('dispatch')

    #     if predefind_event(page_event_file_path, e_name):
    #         continue
    #     def_events_content += Jinja2Utils.render("event.jinja2",
    #                                              {'event': e_name,
    #                                               'type': e_dispatch_path})

    # FileUtil.replace_content(page_event_file_path, r"([\w\W]*)(};)",
    #                          r"\g<1>%s\n\g<2>" % def_events_content)


def render_routes(path, file_name, home_path, models=[]):
    route_id = PageUtils.get_route_id(path, file_name)
    component = "pages%s/%s" % (path, file_name)

    # 在routes文件中匹配routeid,如果找到则不再维护.(力图只为当前page添加一次route信息)
    if FileUtil.match_content(file_path=route_file,
                              match="'%s':" % route_id):
        return

    route_info = Jinja2Utils.render("route_item.jinja2",
                                    {'component': component,
                                     'routeId': route_id,
                                     'models': models
                                     })
    return route_info


ele = jsonFileUtil.getJsonFile(
    "/Users/keel2008/work/developer/04_Projects/winit/ws-agent/app/modules/jinja2/page.json")

print render_page_elements("page", ele)


